package com.example.demo.base

import androidx.annotation.VisibleForTesting
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.demo.base.intent.Action
import com.example.demo.base.model.Effect
import com.example.demo.base.model.State
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch

/**
 * BaseViewModel: 实现 MVI 架构中的核心逻辑
 * View -> Action -> ViewModel -> State/Effect -> View
 *
 * @param A [Action] 用户交互或外部事件
 * @param S [State] UI 状态（冷、持久）
 * @param E [Effect] 一次性副作用（热、瞬时），如 Toast、Navigation
 */
abstract class BaseViewModel<A : Action, S : State, E : Effect> : ViewModel() {

    // ========================
    // Action (输入事件)
    // ========================

    /**
     * 内部 Channel 用于接收 Action
     * 使用 BUFFERED 防止快速点击丢失，也可设为 CONFLATED（去重最新）
     */
    private val _action = Channel<A>(capacity = Channel.BUFFERED)

    /**
     * 外部可发送 Action 的通道（例如来自 Worker、Service）
     */
    val actionChannel: SendChannel<A> get() = _action

    // ========================
    // State (UI 状态)
    // ========================

    /**
     * 可变共享流，用于发射最新的 UI 状态
     * 不设 replay，避免内存泄漏；由 View 决定是否缓存
     */
    private val _state = MutableSharedFlow<S>()

    /**
     * 对外暴露的 State Flow，自动去重
     * 使用 distinctUntilChanged 避免重复渲染
     */
    val state: Flow<S> = _state
        .distinctUntilChanged()

    // ========================
    // Effect (副作用)
    // ========================

    /**
     * 可变共享流，用于发射一次性 UI 副作用（如导航、弹窗）
     * replay = 0：确保 Effect 只被消费一次
     */
    private val _effect = MutableSharedFlow<E>(replay = 0, extraBufferCapacity = 10)

    /**
     * 对外暴露的 Effect Flow
     * 使用 WhileSubscribed 减少资源占用
     */
    val effect: Flow<E> = _effect.asSharedFlow()

    // ========================
    // 初始化：监听 Action
    // ========================

    init {
        viewModelScope.launch {
            _action.receiveAsFlow()
                .catch { e ->
                    handleActionException(e)
                }
                .collect { action ->
                    handleAction(action)
                }
        }
    }

    // ========================
    // Action 处理
    // ========================

    /**
     * 发送一个 Action（从 UI 层调用）
     */
    fun sendAction(action: A) {
        viewModelScope.launch {
            _action.send(action)
        }
    }

    /**
     * 非挂起方式发送 Action（适合从非协程环境调用）
     */
    fun offerAction(action: A): Boolean = _action.trySend(action).isSuccess

    /**
     * 处理单个 Action
     */
    private suspend fun handleAction(action: A) {
        val currentState = getCurrentState()
        onAction(action, currentState)
    }

    /**
     * 子类实现具体业务逻辑
     */
    protected abstract fun onAction(action: A, state: S?)

    /**
     * 异常处理（可重写）
     */
    protected open fun handleActionException(exception: Throwable) {
        // 默认打印，可重写上报
        exception.printStackTrace()
    }

    // ========================
    // State/Effect 发射
    // ========================

    /**
     * 安全发射新状态（挂起）
     */
    protected suspend fun emitState(state: S) {
        _state.emit(state)
    }

    protected fun emitState(builder: suspend () -> S?) = viewModelScope.launch {
        builder()?.let { _state.emit(it) }
    }
    protected fun emitEffect(builder: suspend () -> E?) = viewModelScope.launch {
        builder()?.let { _effect.emit(it) }
    }
    /**
     * 安全发射副作用（挂起）
     */
    protected suspend fun emitEffect(effect: E) {
        _effect.emit(effect)
    }

    /**
     * 非挂起发射状态（返回是否成功）
     */
    @VisibleForTesting
    fun tryEmitState(state: S): Boolean = _state.tryEmit(state)

    /**
     * 非挂起发射 Effect（返回是否成功）
     */
    @VisibleForTesting
    fun tryEmitEffect(effect: E): Boolean = _effect.tryEmit(effect)

    // ========================
    // 辅助方法
    // ========================

    /**
     * 获取当前最新状态（非挂起，取缓存）
     * 注意：如果从未发射过状态，返回 null
     */
    fun getCurrentState(): S? = _state.replayCache.lastOrNull()

    /**
     * 清空所有状态（可选：用于重置）
     */
    @VisibleForTesting
    fun clearState() {
        // SharedFlow 无法清空 replayCache，只能重新创建
        // 若需此功能，可考虑封装或使用 StateFlow + reset
    }

    // ========================
    // 生命周期
    // ========================

    /**
     * 可选：重写 onCleared()
     */
    override fun onCleared() {
        super.onCleared()
        // Channel 会随 viewModelScope 自动关闭
    }
}